package com.fanrui.code.socket.netty.server;

import com.fanrui.code.util.logger.Stdout;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public abstract class SocketServer {

	// 是否完全终止完毕
	private volatile boolean terminated;

	private final String ip;

	private final int port;

	public SocketServer(String ip, int port) {
		this.ip = ip;
		this.port = port;
	}

	private Channel serverChannel;

	/**
	 * 启动服务器，并阻塞当前线程，直到Socket端口关闭。
	 */
	public void startUntilClose() throws InterruptedException {

		this.terminated = false;
		System.setProperty("io.netty.noUnsafe","true");
		// 启动监听端口
		EventLoopGroup boss = new NioEventLoopGroup();
		EventLoopGroup worker = new NioEventLoopGroup();
		try {
			ServerBootstrap boot = new ServerBootstrap().group(boss, worker).channel(NioServerSocketChannel.class)
					.childHandler(this.getChannelInitializer())
					.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
					.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
					.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true);

			if (null == this.ip) {
				this.serverChannel = boot.bind(this.port).sync().channel(); // 绑定所有地址，保留serverChannel等待后续关闭
				
				
				Stdout.GET().info("{} 绑定端口: {} 成功！", this.getClass().getSimpleName(), this.port);
			} else {
				this.serverChannel = boot.bind(this.ip, this.port).sync().channel(); // 绑定指定IP，保留serverChannel等待后续关闭
				Stdout.GET().info("{} 绑定{} : {} 成功！", this.getClass().getSimpleName(), this.ip, this.port);
			}

			this.serverChannel.closeFuture().sync(); // 等待，直到serverChannel被关闭

		} finally {
			boss.shutdownGracefully().sync();
			worker.shutdownGracefully().sync();
		}

		if (null == this.ip) {
			Stdout.GET().info("{} 解除绑定端口: {} 成功！", this.getClass().getSimpleName(), this.port);
		} else {
			Stdout.GET().info("{} 解除绑定{} : {} 成功！", this.getClass().getSimpleName(), this.ip, this.port);
		}

		this.terminated = true;

	}

	/**
	 * 
	 * 用来初始化Channel
	 * 
	 * @return
	 */
	protected abstract ChannelInitializer<SocketChannel> getChannelInitializer();

	/**
	 * 关闭服务器，并阻塞当前线程，直到Socket端口关闭。
	 */
	public void stopAndWait() throws InterruptedException {
		if (null != this.serverChannel) {
			this.serverChannel.close().sync();
			while (!this.terminated) {
				Thread.sleep(100);
			}
		}
	}

}
